#include "winimage.h"

WinImage::WinImage()
    : m_nWidth( 0 )
    , m_nHeight( 0 )
    , m_hBitmap( NULL )
    , m_pBytes( NULL )
{
}

WinImage::~WinImage()
{
}

BOOL WinImage::Copy( WinImage &image )
{
    if( image.m_hBitmap )
    {
        m_nWidth = image.m_nWidth;
        m_nHeight = image.m_nHeight;
        m_hBitmap = image.m_hBitmap;
        m_pBytes = image.m_pBytes;
        return TRUE;
    }

    return FALSE;
}

BOOL WinImage::CreateFromImage( Gdiplus::Image * pImage )
{
    if( !pImage )
    {
        return FALSE;
    }

    int nWidth = pImage->GetWidth();
    int nHeight = pImage->GetHeight();

    if( CreateDIBSection( nWidth, nHeight ) )
    {
        common::WinMemoryDC MemDC( m_hBitmap );
        Gdiplus::Graphics g( (HDC)MemDC );
        g.DrawImage( pImage,
                     Gdiplus::Rect(0, 0, nWidth, nHeight),
                     0, 0, nWidth, nHeight,
                     Gdiplus::UnitPixel );
        return TRUE;
    }

    return FALSE;
}

BOOL WinImage::CreateDIBSection( int nWidth, int nHeight )
{
    if( nWidth <= 0 || nHeight <= 0 )
    {
        return FALSE;
    }

    BITMAPINFO bmi;
    ZeroMemory( &bmi, sizeof(BITMAPINFO) );
    bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
    bmi.bmiHeader.biWidth = nWidth;
    bmi.bmiHeader.biHeight = nHeight;
    bmi.bmiHeader.biPlanes = 1;
    bmi.bmiHeader.biBitCount = 32;
    bmi.bmiHeader.biCompression = BI_RGB;
    bmi.bmiHeader.biSizeImage = nWidth * nHeight * 4;

    if( m_hBitmap != NULL )
    {
        ::DeleteObject( m_hBitmap );
    }

    m_nWidth = 0;
    m_nHeight = 0;
    m_pBytes = NULL;
    m_hBitmap = NULL;

    BYTE* pBits = NULL;
    m_hBitmap = ::CreateDIBSection( NULL, (BITMAPINFO *)&bmi, DIB_RGB_COLORS, (VOID**)&pBits, NULL, 0 );

    if( pBits )
    {
        m_nWidth = nWidth;
        m_nHeight = nHeight;
        m_pBytes = pBits;
        ::memset( (void *)m_pBytes, 0, m_nWidth * m_nHeight * 4 );
        return TRUE;
    }

    return FALSE;
}

BOOL WinImage::DeleteObject()
{
    if( m_hBitmap )
        ::DeleteObject( m_hBitmap );

    m_hBitmap = 0;
    m_nWidth = 0;
    m_nHeight = 0;
    m_pBytes = 0;

    return TRUE;
}

BOOL WinImage::SetAlpha( BYTE byteAlpha, DWORD dwColor )
{
    if( !m_pBytes )
    {
        return FALSE;
    }

    DWORD *pixel = (DWORD*)m_pBytes;
    int nPixelCount = m_nHeight * m_nWidth;

    for( int i = 0; i < nPixelCount; i++, pixel++ )
    {
        if( *pixel == dwColor )
            ((PBYTE)pixel)[3] = byteAlpha;
    }

    return TRUE;
}

BOOL WinImage::TileBlt( HDC hDC, RECT rcDest, int nAlpha )
{
    common::WinMemoryDC MemDC( m_hBitmap );

    int x = rcDest.left;
    int y = rcDest.top;
    int width = rcDest.right - rcDest.left;
    int height = rcDest.bottom - rcDest.top;

    BLENDFUNCTION blend;
    blend.BlendOp = AC_SRC_OVER;
    blend.BlendFlags = 0;
    blend.SourceConstantAlpha = (BYTE)nAlpha;
    blend.AlphaFormat = AC_SRC_ALPHA;

    ::AlphaBlend( hDC, x, y, width, height, MemDC, 0, 0, m_nWidth, m_nHeight, blend );

    return TRUE;
}

BOOL WinImage::GridBlt( HDC hDC, RECT rcDest, RECT rcGrid, int nLength, int nIndex, int nAlpha )
{
    common::WinMemoryDC MemDC( m_hBitmap );

    BLENDFUNCTION blend;
    blend.BlendOp = AC_SRC_OVER;
    blend.BlendFlags = 0;
    blend.SourceConstantAlpha = (BYTE)nAlpha;
    blend.AlphaFormat = AC_SRC_ALPHA;

    if( nLength == 0 )
    {
        nLength = m_nWidth;
    }

    int count = m_nWidth / nLength;
    nIndex = nIndex % count;

    int left = nIndex * nLength;
    int top = 0;
    int right = (nIndex + 1) * nLength;
    int bottom = m_nHeight;

    int gridLeft = rcGrid.left;
    int gridTop = rcGrid.top;
    int gridRight = rcGrid.right;
    int gridBottom = rcGrid.bottom;

    if( gridLeft > 0 && gridTop > 0 )
    {
        ::AlphaBlend( hDC,
            rcDest.left, rcDest.top, gridLeft, gridTop,
            MemDC,
            left, top, gridLeft, gridTop,
            blend );
    }

    if( gridTop > 0 && gridRight > 0 )
    {
        ::AlphaBlend( hDC,
            rcDest.right - gridRight, rcDest.top, gridRight, gridTop,
            MemDC,
            right - gridRight, top, gridRight, gridTop,
            blend );
    }

    if( gridLeft > 0 && gridBottom > 0 )
    {
        ::AlphaBlend( hDC,
            rcDest.left, rcDest.bottom - gridBottom, gridLeft, gridBottom,
            MemDC,
            left, bottom - gridBottom, gridLeft, gridBottom,
            blend );
    }

    if( gridRight > 0 && gridBottom > 0 )
    {
        ::AlphaBlend( hDC,
            rcDest.right - gridRight, rcDest.bottom - gridBottom, gridRight, gridBottom,
            MemDC,
            right - gridRight, bottom - gridBottom, gridRight, gridBottom,
            blend );
    }

    if( gridLeft > 0 )
    {
        int heightDest = rcDest.bottom - rcDest.top - gridTop - gridBottom;
        int heightImage = bottom - top - gridTop - gridBottom;
        ::AlphaBlend( hDC,
            rcDest.left, rcDest.top + gridTop, gridLeft, heightDest,
            MemDC,
            left, top + gridTop, gridLeft, heightImage,
            blend );
    }

    if( gridTop > 0 )
    {
        int widthDest = rcDest.right - rcDest.left - gridLeft - gridRight;
        int widthImage = right - left - gridLeft - gridRight;
        ::AlphaBlend( hDC,
            rcDest.left + gridLeft, rcDest.top, widthDest, gridTop,
            MemDC,
            left + gridLeft, top, widthImage, gridTop,
            blend );
    }

    if( gridRight > 0 )
    {
        int heightDest = rcDest.bottom - rcDest.top - gridTop - gridBottom;
        int heightImage = bottom - top - gridTop - gridBottom;
        ::AlphaBlend( hDC,
            rcDest.right - gridRight, rcDest.top + gridTop, gridRight, heightDest,
            MemDC,
            right - gridRight, top + gridTop, gridRight, heightImage,
            blend );
    }

    if( gridBottom > 0 )
    {
        int widthDest = rcDest.right - rcDest.left - gridRight - gridLeft;
        int widthImage = right - left - gridRight - gridLeft;
        ::AlphaBlend( hDC,
            rcDest.left + gridLeft, rcDest.bottom - gridBottom, widthDest, gridBottom, 
            MemDC,
            left + gridLeft, bottom - gridBottom, widthImage, gridBottom,
            blend );
    }

    if( true )
    {
        int widthDest = rcDest.right - rcDest.left - gridLeft - gridRight;
        int widthImage = right - left - gridLeft - gridRight;
        int heightDest = rcDest.bottom - rcDest.top - gridTop - gridBottom;
        int heightImage = bottom - top - gridTop - gridBottom;
        ::AlphaBlend( hDC,
            rcDest.left + gridLeft, rcDest.top + gridTop, widthDest, heightDest, 
            MemDC,
            left + gridLeft, top + gridTop, widthImage, heightImage,
            blend );
    }

    return TRUE;
}